// --------------------------------------------------------------------
// 线程池的封装
// --------------------------------------------------------------------

#ifndef __THREAD_POOL__
#define __THREAD_POOL__

#include <vector>
#include <mutex>
#include <string>
#include <functional>
#include <unordered_map>
#include <queue>
#include <iostream>
#include "../common.hpp"
#if __cplusplus>=201103L
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <atomic>
#else
#include <pthread.h>
#endif

namespace ymbxUtil
{
    using threadHandler = std::function<void *(void *)>;
#if __cplusplus>=201103L

    class threadPool{
    public:
        threadPool(int num=5):_stop(false){
            for(int i=0;i<num;++i){
                _threads.emplace_back(std::thread([this]{
                    while(true){
                        {
                            std::function<void()> task;
                            {
                            std::unique_lock<std::mutex> lock(this->_mtx);
                            this->_cond.wait(lock,[this]{
                                return this->_stop || !this->_tasks.empty();
                            });
                            if(this->_stop && this->_tasks.empty()){
                                return;
                            }
                            task=this->_tasks.front();
                            this->_tasks.pop();
                            }
                            task();
                        }
                    }
                }));
            }
        }
        // 尾返回类型必须用auto作占位符
        template<class F,class... Args>
        void pushPool(F&& f,Args&&...args){
            using result_type=typename std::result_of<F(Args...)>::type;
            auto task=std::make_shared<std::packaged_task<result_type()>>(std::bind(std::forward<F>(f),std::forward<Args>(args)...));
            {
                std::unique_lock<std::mutex> lock(_mtx);
                if(_stop){
                    throw std::runtime_error("pushPool on stop");
                }
                _tasks.emplace([task]{(*task)();});
            }
            _cond.notify_one();
        }
        ~threadPool(){
            {
                std::unique_lock<std::mutex> lock(_mtx);
                _stop=true;
            }
            _cond.notify_all();
            for(auto& t:_threads){
                t.join();
            }
        }
    private:
        std::vector<std::thread> _threads;
        int _num;
        std::mutex _mtx;
        std::condition_variable _cond;
        std::atomic<bool> _stop;
        // std::function<void()> 通用的函数包装器，表示任何可调用对象(函数、lambda、成员函数)
        std::queue<std::function<void()>> _tasks;
    };

#else
    class Thread
    {
    public:
        enum threadStatus
        {
            EXITED = 0,
            RUNNING
        };
        Thread(int num, threadHandler handler, void *args);
        static void *runhelper(void *args)
        {
            Thread *tid = (Thread *)args;
            (*tid)();
            return nullptr;
        }
        void operator()();
        pthread_t getID();
        int status();
        std::string threadName();
        void join();
        void detach();
        ~Thread();

    private:
        pthread_t _tid;
        std::string _name;
        threadHandler _handler;
        void *_args;
        threadStatus _status;
    };

    template <class T>
    class threadPool
    {
    public:
        threadPool(int num = 5)
        {
            ymbxSock::CreateLog("threadpool");
            pthread_mutex_init(&_mtx, nullptr);
            pthread_cond_init(&_cond, nullptr);
            for (int i = 0; i < num; ++i)
            {
                Thread t(i, threadRoutine, this);
                _threads.push_back(std::move(t));
            }
            LOG_INFO("threadpool","创建线程成功");
        }
        void pushPool(const T &t)
        {
            pthread_mutex_lock(&_mtx);
            _tasks.push(t);
            pthread_cond_signal(&_cond);
            pthread_mutex_unlock(&_mtx);
            LOG_INFO("threadpool","t成功被添加进线程池中");
        }
        static void *threadRoutine(void *args)
        {
            threadPool<T> *tp = static_cast<threadPool<T> *>(args);
            while (true)
            {
                LOG_INFO("threadpool","线程");
                pthread_mutex_lock(&tp->_mtx);
                while (tp->_tasks.empty())
                {
                    pthread_cond_wait(&tp->_cond, &tp->_mtx);
                }
                T t = tp->popPool();
                LOG_INFO("threadpool","线程从线程池中拿出");
                pthread_mutex_unlock(&tp->_mtx);
                t();
                LOG_INFO("threadpool","线程处理结束");
            }
        }
        T popPool()
        {
            T t = _tasks.front();
            _tasks.pop();
            return t;
        }
        ~threadPool()
        {
            for (auto t : _threads)
            {
                t.join();
            }
            pthread_mutex_destroy(&_mtx);
            pthread_cond_destroy(&_cond);
        }

    private:
        std::vector<Thread> _threads;
        int _num;
        std::queue<T> _tasks;
        pthread_mutex_t _mtx;
        pthread_cond_t _cond;
    };
#endif
}
#endif